﻿using System;
using System.Web.Mvc;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using User.Global.Tests.Helper.MockHelper;
using User.Web.Models.Account;
using User.Web.UI.Controllers;
using User.Web.UI.Tests.Unit.CommonTests;

namespace User.Web.UI.Tests.Unit.ControllerTests
{
    [TestClass]
    public class AccountControllerTest : CommonBaseTest
    {
        #region Register
        /// <summary>
        /// Prüfen das auch eine NullReferenceException geworfen wird, wenn kein
        /// MockMembership Repository übergeben wird.
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(NullReferenceException), "IDiMembership is Null")]
        public void Controller_CreationException_IsNull()
        {
            AccountController controller = new AccountController(null, MockAccountMails.Object, MockWebQuerySummary.Object);
        }

        /// <summary>
        /// Für die Registermethode das Kommunikationsproperty AddMessage auf Null setzten
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(NullReferenceException), "AddMessage is Null")]
        public void Register_ExceptionAddMessage_IsNull()
        {
            AccountController controller = AccountController;
            controller.AddMessage = null;
            //Exception wird aufgerufen, da AddMessage Null ist.
            controller.Register(new RegisterModel());
        }

        /// <summary>
        /// Für die Registermethode das Kommunikationsproperty Logger auf Null setzten
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(NullReferenceException), "Logger is Null")]
        public void Register_ExceptionLogger_IsNull()
        {
            AccountController controller = AccountController;
            controller.Logger = null;
            //Exception wird aufgerufen, da AddMessage Null ist.
            controller.Register(new RegisterModel());
        }

        /// <summary>
        /// Für die Registermethode den Modelstate auf false stellen
        /// </summary>
        [TestMethod]
        public void Register_Failed_ModelStateInvalid()
        {
            AccountController controller = AccountController;
            //Modelvalidation auf false stellen!
            controller.ModelState.AddModelError("ErrorKey", "SomeErrortext");
            Mock<RegisterModel> registerModel = new Mock<RegisterModel>();
            ViewResult result = controller.Register(registerModel.Object) as ViewResult;

            //Assert
            Assert.IsNotNull(result);
            Assert.AreEqual("Register", result.ViewName);
            Assert.AreSame(registerModel.Object, result.Model);
        }

        /// <summary>
        /// Für die Registermethode die auf false stellen
        /// </summary>
        [TestMethod]
        public void Register_Failed_WrongRegisterData()
        {
            AccountController controller = AccountController;
            Mock<RegisterModel> registerModel = new Mock<RegisterModel>();
            //Create User schlägt fehl.
            registerModel.Setup(p => p.CreateUser(MockMembership.Object)).Returns(false);

            ViewResult result = controller.Register(registerModel.Object) as ViewResult;

            //Assert
            Assert.IsNotNull(result);
            Assert.AreEqual("Register", result.ViewName);
            Assert.AreSame(registerModel.Object, result.Model);
            registerModel.Verify(p => p.CreateUser(MockMembership.Object), Times.Once);
        }

        /// <summary>
        /// Prüft ob der richtige View für Register angezeigt wird, wenn die Registrierung erfolgreich war.
        /// </summary>
        [TestMethod]
        public void Register_Success()
        {
            AccountController controller = AccountController;
            //RegisterModel Mocken, da wir hier die CreateUserMethode benötigen.
            Mock<RegisterModel> registerModel = new Mock<RegisterModel>();
            registerModel.Setup(p => p.CreateUser(MockMembership.Object)).Returns(true);
            RedirectToRouteResult result = controller.Register(registerModel.Object) as RedirectToRouteResult;

            //Assert
            Assert.IsNotNull(result);
            //Hier gibt es nur die Action, da wir im gleichen Controller bleiben
            Assert.AreEqual("RegisterSuccess", result.RouteValues[ConstTestValues.Action]);
            registerModel.Verify(p => p.CreateUser(MockMembership.Object), Times.Once);
        }

        /// <summary>
        /// Prüft ob der richtige View für Register angezeigt wird.
        /// </summary>
        [TestMethod]
        public void Register_View()
        {
            AccountController controller = AccountController;
            ViewResult viewResult = controller.Register() as ViewResult;

            //Assert
            Assert.IsNotNull(viewResult);
            Assert.AreEqual("Register", viewResult.ViewName);
        }

        /// <summary>
        /// Prüft ob der richtige View für RegisterSuccess angezeigt wird.
        /// </summary>
        [TestMethod]
        public void Register_Success_View()
        {
            AccountController controller = AccountController;
            ViewResult viewResult = controller.RegisterSuccess() as ViewResult;

            //Assert
            Assert.IsNotNull(viewResult);
            Assert.AreEqual("RegisterSuccess", viewResult.ViewName);
        }
        #endregion

        #region Login
        /// <summary>
        /// Logout des aktuellen Users über unseren MockMembership Provider
        /// </summary>
        [TestMethod]
        public void Logoff_Success()
        {
            AccountController controller = AccountController;
            MockMembership.Setup(p => p.Logout());
            RedirectToRouteResult viewResult = controller.Logoff() as RedirectToRouteResult;

            //Assert
            Assert.IsNotNull(viewResult);
            Assert.AreEqual("Index", viewResult.RouteValues[ConstTestValues.Action]);
            Assert.AreEqual("Home", viewResult.RouteValues[ConstTestValues.Controller]);
            MockMembership.Verify(p => p.Logout(), Times.Once);
        }

        /// <summary>
        /// Prüfen ob der Loginvorgang erfolgreich war mit den übergebenen Logindaten, ob 
        /// der richtige View geladen bzw. angezeigt wird.
        /// </summary>
        [TestMethod]
        public void Login_Success()
        {
            AccountController controller = AccountController;
            LoginModel loginModel = new LoginModel();
            loginModel.Username = "squadwuschel";
            loginModel.Password = "testname";
            RedirectToRouteResult viewResult = controller.Login(loginModel) as RedirectToRouteResult;

            //Assert
            Assert.IsNotNull(viewResult);
            Assert.AreEqual("Index", viewResult.RouteValues[ConstTestValues.Action]);
            Assert.AreEqual("Home", viewResult.RouteValues[ConstTestValues.Controller]);
        }

        /// <summary>
        /// Prüfen welcher View angezeigt wird, wenn der Loginvorgang nicht erfolgreich war, da es sich um fehlerhafte Logindaten handelt.
        /// </summary>
        [TestMethod]
        public void Login_Failed_WrongLoginData()
        {
            AccountController controller = AccountController;
            LoginModel loginModel = new LoginModel();
            //Fehlerhafte Logindaten angeben
            loginModel.Username = "squadwuschel2";
            loginModel.Password = "testname";
            ViewResult viewResult = controller.Login(loginModel) as ViewResult;

            //Assert
            Assert.IsNotNull(viewResult);
            Assert.AreEqual("Login", viewResult.ViewName);
            //Prüfen das auch die gleichen Modeldaten wieder angezeigt werden bzw. zurückgegeben werden, bei einem Fehler
            Assert.AreEqual(loginModel, viewResult.Model);
        }

        /// <summary>
        /// Prüfen welcher View angezeigt wird, wenn der Loginvorgang nicht erfolgreich war, da es sich um fehlerhafte Logindaten handelt.
        /// </summary>
        [TestMethod]
        public void Login_Failed_ModelStateInvalid()
        {
            AccountController controller = AccountController;
            LoginModel loginModel = new LoginModel();
            //Fehlerhafte Logindaten angeben
            loginModel.Username = "squadwuschel";
            loginModel.Password = "testname";
            //Dem Modelstate einfach einen Fehler hinzufügen, hier ist es egal was genau in Key und Value steht.
            //Da der Modelstate dann einen Fehler enthält, findet kein Login statt.
            controller.ModelState.AddModelError("ErrorKey", "FehlerText");
            ViewResult viewResult = controller.Login(loginModel) as ViewResult;

            //Assert
            Assert.IsNotNull(viewResult);
            Assert.AreEqual("Login", viewResult.ViewName);
            Assert.AreEqual(loginModel, viewResult.Model);
        }

        /// <summary>
        /// Beim Erstellen des Views werden die CommunicationsObjekte für 
        /// Logger und Messages übergeben, Logger wird jetzt mit Null initialisert und 
        /// der View wird eine Exception werfen.
        /// </summary>
        [ExpectedException(typeof(NullReferenceException), "Logger is Null")]
        [TestMethod]
        public void Login_ExceptionLogger_IsNull()
        {
            AccountController controller = AccountController;
            controller.Logger = null;
            LoginModel loginModel = new LoginModel();
            //Exception erwartet das Logger bzw. AddMessage Null sind.
            controller.Login(loginModel);
        }

        /// <summary>
        /// Beim Erstellen des Views werden die CommunicationsObjekte für 
        /// Logger und Messages übergeben, AddMessage werden jetzt mit Null initialisert und 
        /// der View wird eine Exception werfen.
        /// </summary>
        [ExpectedException(typeof(NullReferenceException), "AddMessage is Null")]
        [TestMethod]
        public void Login_ExceptionAddMessage_IsNull()
        {
            AccountController controller = AccountController;
            controller.AddMessage = null;
            LoginModel loginModel = new LoginModel();
            //Exception erwartet das Logger bzw. AddMessage Null sind.
            controller.Login(loginModel);
        }

        /// <summary>
        /// Prüfen ob das Anzeigen des Login Views "funktioniert"
        /// </summary>
        [TestMethod]
        public void Login_View()
        {
            AccountController controller = AccountController;
            ViewResult viewResult = controller.Login() as ViewResult;

            //Assert
            Assert.IsNotNull(viewResult);
            Assert.AreEqual("Login", viewResult.ViewName);
        }
        #endregion
    }
}
